package org.eiahe.hr.salary.task;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eiahe.hr.salary.domain.SalaryStructure;
import org.eiahe.hr.salary.domain.dto.SalaryGenerateStatDto;
import org.eiahe.hr.salary.mapper.SalaryStructureMapper;
import org.eiahe.hr.salary.service.IFinanceService;
import org.eiahe.hr.salary.service.ISalaryStatisticsService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

/**
 * 薪资管理自动任务
 * 包含定时生成统计、银行文件等自动化功能
 *
 * @author zhangnn
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class SalaryAutoTask {

    private final ISalaryStatisticsService salaryStatisticsService;
    private final IFinanceService financeService;
    private final SalaryStructureMapper salaryStructureMapper;

    /**
     * 每月20日凌晨2点自动生成上月薪资统计
     * 用于生成月度薪资报表和统计数据
     */
    @Scheduled(cron = "0 0 2 20 * ?")
    public void autoGenerateMonthlyStatistics() {
        log.info("开始执行月度薪资统计自动生成任务");

        try {
            // 获取上个月的年月
            LocalDate lastMonth = LocalDate.now().minusMonths(1);
            String yearMonth = lastMonth.format(DateTimeFormatter.ofPattern("yyyyMM"));

            // 构建统计生成参数
            SalaryGenerateStatDto dto = new SalaryGenerateStatDto();
            dto.setYearMonth(yearMonth);
            // 默认统计所有部门，实际应用中可以根据需要调整
            dto.setDepartmentIds(Arrays.asList(0L)); // 0表示所有部门

            // 生成薪资统计
            salaryStatisticsService.generateStatistics(dto);

            log.info("月度薪资统计自动生成任务执行完成，年月：{}", yearMonth);
        } catch (Exception e) {
            log.error("月度薪资统计自动生成任务执行失败", e);
        }
    }

    /**
     * 每月发薪日前一天凌晨3点自动生成银行代发文件
     * 发薪日默认为每月15日
     */
    @Scheduled(cron = "0 0 3 14 * ?")
    public void autoGenerateBankPaymentFile() {
        log.info("开始执行银行代发文件自动生成任务");

        try {
            // 获取当前年月
            String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));

            // 生成银行代发文件
            String filePath = financeService.generateBankPaymentFile(yearMonth);

            if (filePath != null) {
                log.info("银行代发文件自动生成成功，文件路径：{}", filePath);
            } else {
                log.warn("银行代发文件自动生成失败，可能没有待发放的薪资数据");
            }
        } catch (Exception e) {
            log.error("银行代发文件自动生成任务执行失败", e);
        }
    }

    /**
     * 每日凌晨4点执行薪资数据校验
     * 校验薪资数据的准确性和完整性
     */
    @Scheduled(cron = "0 0 4 * * ?")
    public void autoValidateSalaryData() {
        log.info("开始执行薪资数据自动校验任务");

        try {
            // 获取最近一个月的薪资数据进行校验
            LocalDate currentDate = LocalDate.now();
            String currentYearMonth = currentDate.format(DateTimeFormatter.ofPattern("yyyyMM"));

            // 查询当月薪资数据
            List<SalaryStructure> salaryList = salaryStructureMapper.selectList(null);

            int errorCount = 0;
            for (SalaryStructure salary : salaryList) {
                // 校验应发工资计算是否正确
                if (!validateGrossSalary(salary)) {
                    log.warn("员工{}({})的应发工资计算不正确", salary.getEmployeeName(), salary.getEmployeeNo());
                    errorCount++;
                }

                // 校验社保公积金合计计算是否正确
                if (!validateSocialHousingTotal(salary)) {
                    log.warn("员工{}({})的社保公积金合计计算不正确", salary.getEmployeeName(), salary.getEmployeeNo());
                    errorCount++;
                }

                // 校验实发工资计算是否正确
                if (!validateNetSalary(salary)) {
                    log.warn("员工{}({})的实发工资计算不正确", salary.getEmployeeName(), salary.getEmployeeNo());
                    errorCount++;
                }
            }

            log.info("薪资数据自动校验任务执行完成，共校验{}条数据，发现{}个错误", salaryList.size(), errorCount);
        } catch (Exception e) {
            log.error("薪资数据自动校验任务执行失败", e);
        }
    }

    /**
     * 校验应发工资计算是否正确
     * 应发工资 = 基本工资 + 绩效工资 + 职务津贴 + 误餐补助 + 其他调整 - 缺勤扣款 - 餐费扣款
     */
    private boolean validateGrossSalary(SalaryStructure salary) {
        try {
            BigDecimal calculatedGross = BigDecimal.ZERO;

            // 累加正向金额
            if (salary.getBaseSalary() != null)
                calculatedGross = calculatedGross.add(salary.getBaseSalary());
            if (salary.getPerformanceSalary() != null)
                calculatedGross = calculatedGross.add(salary.getPerformanceSalary());
            if (salary.getDutyAllowance() != null)
                calculatedGross = calculatedGross.add(salary.getDutyAllowance());
            if (salary.getMealAllowance() != null)
                calculatedGross = calculatedGross.add(salary.getMealAllowance());
            if (salary.getOtherAdjustment() != null)
                calculatedGross = calculatedGross.add(salary.getOtherAdjustment());

            // 扣除负向金额
            if (salary.getAbsenceDeduction() != null)
                calculatedGross = calculatedGross.subtract(salary.getAbsenceDeduction());
            if (salary.getMealDeduction() != null)
                calculatedGross = calculatedGross.subtract(salary.getMealDeduction());

            // 比较计算结果与存储的应发工资
            if (salary.getGrossSalary() != null) {
                return salary.getGrossSalary().compareTo(calculatedGross) == 0;
            }
            return calculatedGross.compareTo(BigDecimal.ZERO) == 0;
        } catch (Exception e) {
            log.error("校验应发工资时发生错误", e);
            return false;
        }
    }

    /**
     * 校验社保公积金合计计算是否正确
     * 社保公积金合计 = 养老扣款 + 失业扣款 + 医疗扣款 + 大额医疗扣款 + 公积金扣款
     */
    private boolean validateSocialHousingTotal(SalaryStructure salary) {
        try {
            BigDecimal calculatedTotal = BigDecimal.ZERO;

            // 累加各项扣款
            if (salary.getPensionDeduction() != null)
                calculatedTotal = calculatedTotal.add(salary.getPensionDeduction());
            if (salary.getUnemploymentDeduction() != null)
                calculatedTotal = calculatedTotal.add(salary.getUnemploymentDeduction());
            if (salary.getMedicalDeduction() != null)
                calculatedTotal = calculatedTotal.add(salary.getMedicalDeduction());
            if (salary.getMajorMedicalDeduction() != null)
                calculatedTotal = calculatedTotal.add(salary.getMajorMedicalDeduction());
            if (salary.getHousingFundPersonal() != null)
                calculatedTotal = calculatedTotal.add(salary.getHousingFundPersonal());

            // 比较计算结果与存储的合计
            if (salary.getSocialHousingTotal() != null) {
                return salary.getSocialHousingTotal().compareTo(calculatedTotal) == 0;
            }
            return calculatedTotal.compareTo(BigDecimal.ZERO) == 0;
        } catch (Exception e) {
            log.error("校验社保公积金合计时发生错误", e);
            return false;
        }
    }

    /**
     * 校验实发工资计算是否正确
     * 实发工资 = 应发工资 - 社保个人扣款 - 公积金扣款 - 个人所得税
     */
    private boolean validateNetSalary(SalaryStructure salary) {
        try {
            BigDecimal calculatedNet = BigDecimal.ZERO;

            // 从应发工资开始
            if (salary.getGrossSalary() != null)
                calculatedNet = salary.getGrossSalary();

            // 扣除各项扣款
            if (salary.getSocialInsurancePersonal() != null)
                calculatedNet = calculatedNet.subtract(salary.getSocialInsurancePersonal());
            if (salary.getHousingFundPersonal() != null)
                calculatedNet = calculatedNet.subtract(salary.getHousingFundPersonal());
            if (salary.getPersonalTax() != null)
                calculatedNet = calculatedNet.subtract(salary.getPersonalTax());

            // 比较计算结果与存储的实发工资
            if (salary.getNetSalary() != null) {
                return salary.getNetSalary().compareTo(calculatedNet) == 0;
            }
            return calculatedNet.compareTo(BigDecimal.ZERO) == 0;
        } catch (Exception e) {
            log.error("校验实发工资时发生错误", e);
            return false;
        }
    }
}
